package edu.thu.studio.ormdesigner.editor.dialog.tab.table;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.PlatformUI;

import edu.thu.studio.ormdesigner.Activator;
import edu.thu.studio.ormdesigner.common.AbstractDialog;
import edu.thu.studio.ormdesigner.common.CompositeFactory;
import edu.thu.studio.ormdesigner.editor.dialog.tab.table.sub.ColumnDialog;
import edu.thu.studio.ormdesigner.model.orm.table.Column;
import edu.thu.studio.ormdesigner.model.orm.table.Key;
import edu.thu.studio.ormdesigner.model.orm.table.RefColumn;
import edu.thu.studio.ormdesigner.model.orm.table.RefColumnSet;
import edu.thu.studio.ormdesigner.util.Properties;
import edu.thu.studio.ormdesigner.util.Utils;

public class TableComposite extends Composite {

	private static final int DEFAULT_HEIGHT = 200;

	public static final int NAME_WIDTH = 150;

	private static final int TYPE_WIDTH = 130;

	public static final int UNIQUE_KEY_WIDTH = 90;
	
	public static final int DEFAULT_WITH = 80;

	private Table table;

	private Button columnAddButton;

	private Button columnEditButton;

	private Button columnDeleteButton;

	private Button upButton;

	private Button downButton;

	private edu.thu.studio.ormdesigner.model.orm.table.Table ormTable;

	private Map<Column, TableEditor[]> columnNotNullCheckMap = new HashMap<Column, TableEditor[]>();

	private List<Column> columnList;

	private ColumnDialog columnDialog;

	private boolean buttonDisplay;

	private int height;

	public TableComposite(Composite parent,
			edu.thu.studio.ormdesigner.model.orm.table.Table ormTable,
			List<Column> columnList, AbstractDialog parentDialog,
			boolean buttonDisplay, int horizontalSpan) {
		super(parent, SWT.NONE);

		this.height = DEFAULT_HEIGHT;

		this.ormTable = ormTable;
		this.columnList = columnList;

		this.buttonDisplay = buttonDisplay;

		GridData gridData = new GridData();
		gridData.horizontalSpan = horizontalSpan;
		gridData.grabExcessVerticalSpace = true;
		gridData.verticalAlignment = GridData.FILL;

		this.setLayoutData(gridData);

		this.createComposite();
		this.initComposite();
	}

	private void createComposite() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.marginWidth = 0;
		gridLayout.numColumns = 1;

		this.setLayout(gridLayout);

		this.createTable();

		if (this.buttonDisplay) {
			this.createButton();
			this.setButtonEnabled(false);
		}

	}

	private void createTable() {
		this.table = CompositeFactory.createTable(this, this.height, 3);

		table.addListener(SWT.PaintItem, new Listener() {

			public void handleEvent(Event event) {
				if (event.index == 0 || event.index == 1) {
					TableItem tableItem = (TableItem) event.item;

					Image tmpImage = (Image) tableItem.getData(String
							.valueOf(event.index));

					if (tmpImage != null) {
						int tmpWidth = tableItem.getBounds(event.index).width;
						int tmpHeight = tableItem.getBounds().height;

						int tmpX = tmpImage.getBounds().width;
						tmpX = (tmpWidth / 2 - tmpX / 2);
						int tmpY = tmpImage.getBounds().height;
						tmpY = (tmpHeight / 2 - tmpY / 2);
						if (tmpX <= 0)
							tmpX = event.x;
						else
							tmpX += event.x;
						if (tmpY <= 0)
							tmpY = event.y;
						else
							tmpY += event.y;

						event.gc.drawImage(tmpImage, tmpX, tmpY);
					}
				}
			}
		});

		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_pk, -1, SWT.CENTER);
		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_fk, -1, SWT.CENTER);
		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_table_column_cname, NAME_WIDTH,
				SWT.NONE);
		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_table_column_ccode, NAME_WIDTH,
				SWT.NONE);
		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_table_column_datatype, TYPE_WIDTH,
				SWT.NONE);
		
		/*CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_table_column_length, DEFAULT_WITH, SWT.CENTER);
		CompositeFactory
				.createTableColumn(this.table,
						Properties.diagram_label_table_column_precision, DEFAULT_WITH,
						SWT.CENTER);*/
		
		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_table_column_domain_radio, DEFAULT_WITH,
				SWT.CENTER);
		CompositeFactory.createTableColumn(this.table,
				Properties.diagram_label_table_column_null, DEFAULT_WITH, SWT.CENTER);

		this.table.addSelectionListener(new SelectionAdapter() {

			/**
			 * {@inheritDoc}
			 */
			@Override
			public void widgetSelected(SelectionEvent e) {
				int index = table.getSelectionIndex();
				selectTable(index);
			}

		});

		if (this.buttonDisplay) {
			this.table.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseDoubleClick(MouseEvent e) {
					Column targetColumn = getTargetColumn();
					if (null == targetColumn) {
						return;
					}
					addOrEditColumn(targetColumn, false);
				}
			});
		}

		this.table.pack();
	}

	private void createButton() {
		Composite buttonComposite = CompositeFactory.createChildComposite(this,
				1, 8);

		this.columnAddButton = CompositeFactory.createSmallButton(
				buttonComposite, Properties.diagram_label_table_column_add);
		this.columnAddButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				addOrEditColumn(null, true);
			}
		});

		this.columnEditButton = CompositeFactory.createSmallButton(
				buttonComposite, Properties.diagram_label_table_column_edit);
		this.columnEditButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				Column targetColumn = getTargetColumn();
				addOrEditColumn(targetColumn, false);
			}

		});

		this.columnDeleteButton = CompositeFactory.createSmallButton(
				buttonComposite, Properties.diagram_label_table_column_delete);
		this.columnDeleteButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int index = table.getSelectionIndex();

				removeColumn();

				if (index >= table.getItemCount()) {
					index = table.getItemCount() - 1;
				}

				selectTable(index);
			}

		});

		CompositeFactory.filler(buttonComposite, 1, 30);

		this.upButton = CompositeFactory.createSmallButton(buttonComposite,
				Properties.diagram_label_table_column_up);
		this.upButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				upColumn();
			}

		});

		this.downButton = CompositeFactory.createSmallButton(buttonComposite,
				Properties.diagram_label_table_column_down);
		this.downButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				downColumn();
			}

		});

	}

	@Override
	public void setEnabled(boolean enabled) {
		super.setEnabled(enabled);
		if (this.buttonDisplay) {
			this.columnAddButton.setEnabled(enabled);
			this.columnEditButton.setEnabled(false);
			this.columnDeleteButton.setEnabled(false);
			this.upButton.setEnabled(false);
			this.downButton.setEnabled(false);
		}
	}

	private void setButtonEnabled(boolean enabled) {
		if (this.buttonDisplay) {
			this.columnEditButton.setEnabled(enabled);
			this.columnDeleteButton.setEnabled(enabled);
			this.upButton.setEnabled(enabled);
			this.downButton.setEnabled(enabled);
		}
	}

	private void initComposite() {
		if (this.columnList != null) {
			for (Column column : this.columnList) {
				TableItem tableItem = new TableItem(this.table, SWT.NONE);
				this.column2TableItem(column, tableItem);
			}
		}
	}

	private void column2TableItem(Column column, TableItem tableItem) {
		this.disposeCheckBox(column);

		Column normalColumn = column;
		
		// 设置主键
		if (normalColumn.getPrimary()) {
			tableItem.setData("0",
					Activator.getImage(Properties.icon_column_pk));
		} else {
			tableItem.setData("0", null);
		}

		// 设置外键
		if (this.ormTable.getReferences().isFk(normalColumn.getId())) {
			tableItem.setData("1",
					Activator.getImage(Properties.icon_column_fk));
		} else {
			tableItem.setData("1", null);
		}

		// 殒名
		tableItem.setText(2, Utils.null2blank(normalColumn.getName()));
		// 编码
		tableItem.setText(3, Utils.null2blank(normalColumn.getCode()));

		if (!normalColumn.hasDomain()) {
			// 类型
			tableItem.setText(4, Utils.null2blank(normalColumn.getDataType()));
			
			// 长度
			/*if(null != normalColumn.getLength()){
				tableItem.setText(5, Utils.null2blank(String.valueOf(normalColumn.getLength())));
			}*/
			
			// 精度
			/*if(null != normalColumn.getPrecision()){
				tableItem.setText(6, Utils.null2blank(String.valueOf(normalColumn.getPrecision())));
			}*/
			// 域
			tableItem.setText(5, Properties.diagram_label_table_column_isnotdomain);
		} else {
			// 类型
			tableItem.setText(4, Utils.null2blank(normalColumn.getDomainObject().getDataType()));
			
			// 长度
			/*if(null != normalColumn.getDomainObject().getLength()){
				tableItem.setText(5, Utils.null2blank(String.valueOf(normalColumn.getDomainObject().getLength())));
			}*/
			
			// 精度
			/*if(null != normalColumn.getDomainObject().getPrecision()){
				tableItem.setText(6, Utils.null2blank(String.valueOf(normalColumn.getDomainObject().getPrecision())));
			}*/
			
			// 不允许为空
			tableItem.setText(5,"[ " + normalColumn.getDomainName() + " ]");
		}

		this.setTableEditor(normalColumn, tableItem);

	}

	private void disposeCheckBox(Column column) {
		TableEditor[] oldEditors = this.columnNotNullCheckMap.get(column);

		if (oldEditors != null) {
			for (TableEditor oldEditor : oldEditors) {
				if (oldEditor.getEditor() != null) {
					oldEditor.getEditor().dispose();
					oldEditor.dispose();
				}
			}

			this.columnNotNullCheckMap.remove(column);
		}
	}

	private void addOrEditColumn(Column targetColumn, boolean add) {

		this.columnDialog = new ColumnDialog(this.getShell(), Utils
				.getActiveEditor().getORMModel().getDomains());
		this.columnDialog.setTargetColumn(targetColumn,this.columnList);

		if (this.columnDialog.open() == IDialogConstants.OK_ID) {
			Column column = this.columnDialog.getColumn();

			addTableData(column, add);
		}

		this.table.forceFocus();
	}

	private void addTableData(Column column, boolean add) {
		int index = this.table.getSelectionIndex();
		TableItem tableItem = null;
		Column copyColumn = null;

		if (add) {
			tableItem = new TableItem(table, SWT.NONE);
			this.columnList.add(column);
			this.column2TableItem(column, tableItem);
		} else {
			tableItem = this.table.getItem(index);
			copyColumn = this.columnList.get(index);
			Column.copyData(column, copyColumn);
			this.column2TableItem(copyColumn, tableItem);
		}

		initKey();
	}

	private void initKey() {
		// 更新主键
		Key key = this.ormTable.getKey();
		if (null == key || null == key.getRefColumns()) {
			key = new Key();
			key.setId(Utils.getUUID());
			this.ormTable.setKey(key);
			RefColumnSet refColumnSet = new RefColumnSet();
			refColumnSet.setId(Utils.getUUID());
			this.ormTable.getKey().setRefColumns(refColumnSet);
		}
		this.ormTable.getKey().removeAll();

		String keyName = "",keyCode="";
		int i=0;
		for (Column _column : columnList) {
			if(_column.getPrimary()){
				RefColumn refColumn = new RefColumn();
				refColumn.setId(_column.getId());
				refColumn.setName(_column.getName());
				if(i>0){
					keyName += "_";
					keyCode += "_";
				}
				keyName += _column.getName();
				keyCode += _column.getCode();
				
				this.ormTable.getKey().getRefColumns().addObject(refColumn);
				i++;
			}
		}
		this.ormTable.getKey().setName(keyName);
		this.ormTable.getKey().setCode(keyCode);
	}

	private void setTableEditor(final Column normalColumn, TableItem tableItem) {

		final Button notNullCheckButton = new Button(this.table, SWT.CHECK);
		notNullCheckButton.pack();

		TableEditor[] editors = new TableEditor[1];

		editors[0] = new TableEditor(this.table);

		editors[0].minimumWidth = notNullCheckButton.getSize().x;
		editors[0].horizontalAlignment = SWT.CENTER;
		editors[0].setEditor(notNullCheckButton, tableItem, 6);

		if (normalColumn.getMandatory()) {
			notNullCheckButton.setSelection(true);
		} else {
			notNullCheckButton.setSelection(false);
		}

		if (normalColumn.getPrimary()) {
			notNullCheckButton.setEnabled(false);
		} else {
			notNullCheckButton.setEnabled(true);
			notNullCheckButton.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					boolean notnull = notNullCheckButton.getSelection();

					setNotNull(normalColumn, notnull);

					super.widgetSelected(e);
				}
			});
		}

		this.columnNotNullCheckMap.put(normalColumn, editors);

	}

	private void selectTable(int index) {
		this.table.select(index);

		if (index >= 0) {
			this.setButtonEnabled(true);
		} else {
			this.setButtonEnabled(false);
		}
	}

	private Column getTargetColumn() {
		Column column = null;

		int index = this.table.getSelectionIndex();

		if (index != -1) {
			Column targetColumn = this.columnList.get(index);

			if (targetColumn instanceof Column) {
				column = targetColumn;
			}
		}

		return column;
	}

	private void removeColumn() {
		int index = this.table.getSelectionIndex();

		if (index != -1) {
			Column column = this.columnList.get(index);

			if (column.getPrimary()) {
				// 提示主键不能删
				this.setMessage(Properties.error_column_notdelete);
			} else if (this.ormTable.getReferences().isFk(column.getId())) {
				// 提示外键不能删除
				this.setMessage(Properties.error_column_notdelete);
			} else {
				removeColumn(index);
			}
		}
		// this.parentDialog.validate();
	}

	public void removeColumn(int index) {
		Column column = this.columnList.get(index);

		this.table.remove(index);
		this.columnList.remove(index);
		this.disposeCheckBox(column);

		for (int i = index; i < this.table.getItemCount(); i++) {
			TableItem tableItem = this.table.getItem(i);
			column = this.columnList.get(i);
			this.disposeCheckBox(column);
			this.setTableEditor(column, tableItem);
		}
	}

	private void upColumn() {
		int index = this.table.getSelectionIndex();

		if (index != -1 && index != 0) {
			this.changeColumn(index - 1, index);
			this.table.setSelection(index - 1);
		}
	}

	private void downColumn() {
		int index = this.table.getSelectionIndex();

		if (index != -1 && index != table.getItemCount() - 1) {
			this.changeColumn(index, index + 1);
			table.setSelection(index + 1);
		}
	}

	private void changeColumn(int index1, int index2) {
		Column column1 = this.columnList.remove(index1);
		Column column2 = null;

		if (index1 < index2) {
			column2 = this.columnList.remove(index2 - 1);
			this.columnList.add(index1, column2);
			this.columnList.add(index2, column1);

		} else if (index1 > index2) {
			column2 = this.columnList.remove(index2);
			this.columnList.add(index1 - 1, column2);
			this.columnList.add(index2, column1);
		}

		TableItem[] tableItems = this.table.getItems();

		this.column2TableItem(column1, tableItems[index2]);
		this.column2TableItem(column2, tableItems[index1]);
	}

	private void setNotNull(Column setColumn, boolean mandatory) {
		for (Column column : columnList) {
			if (column.getId().equals(setColumn.getId())) {
				column.setMandatory(mandatory);
			}
		}
	}

	private void setMessage(String message) {
		MessageBox messageBox = new MessageBox(PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow().getShell(), SWT.ICON_ERROR | SWT.OK);
		messageBox.setText(Properties.error_dialog_title_error);
		messageBox.setMessage(message);
		messageBox.open();
	}

}
